package com.swedne.test.proxy_reflectRelate;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;


import com.swedne.test.R;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import static android.os.Build.VERSION.SDK_INT;

public class HookTestActivity extends Activity {

    private static final String TAG = "HookTestActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hook_test);
        try {
            hookNotificationManager(this);
        } catch (Exception e) {
            e.printStackTrace();
        }

        final Button btn_test = findViewById(R.id.btn_test);
        btn_test.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("fang " + TAG, "onClick: 点击事件");
            }
        });
        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                hookOnClickListener(btn_test);
            }
        });


    }

    private void initHook() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
            return;
        }
        try {
            Method forName = Class.class.getDeclaredMethod("forName", String.class);
            Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
            Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
            Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
            Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
            Object sVmRuntime = getRuntime.invoke(null);
            setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{new String[]{"L"}});
        } catch (Throwable e) {
            Log.e("[error]", "reflect bootstrap failed:", e);
        }
    }

    /**
     * 使用继承需要改动的代码太多，用反射直接插入
     * @param view
     */
    private void hookOnClickListener(Button view) {
//        initHook();
        try {
//            Class<?> viewClass = Class.forName("android.view.View");
//            Method getListenerInfo = viewClass.getMethod("getListenerInfo");
            Method getListenerInfo = View.class.getMethod("getListenerInfo");
            getListenerInfo.setAccessible(true);
            Object listenerInfo = getListenerInfo.invoke(view);
            Class<?> listenerInfoCls = Class.forName("android.view.View$ListenerInfo");
            Field mOnClickListener = listenerInfoCls.getDeclaredField("mOnClickListener");
            mOnClickListener.setAccessible(true);
            View.OnClickListener originClick = (View.OnClickListener) mOnClickListener.get(listenerInfo);
            View.OnClickListener hookClickListener = new HookOnClickListener(originClick);
            mOnClickListener.set(originClick, hookClickListener);
            Log.i("fang " + TAG, "hookOnClickListener: 2");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class HookOnClickListener implements View.OnClickListener {

        private View.OnClickListener originClickListener;

        public HookOnClickListener(View.OnClickListener originClickListener) {
            this.originClickListener = originClickListener;
        }

        @Override
        public void onClick(View v) {
            Log.i("fang " + TAG, "onClick: 点击事件前");
            if (originClickListener != null) {
                originClickListener.onClick(v);
            }
            Log.i("fang " + TAG, "onClick: 点击事件后");
        }
    }


    public void TestNotify(View view) {
        notifyTest2();
    }

    private void notifyTest() {
        Notification.Builder builder = new Notification.Builder(this);
        Intent push = new Intent(this, HookTestActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, push, 0);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        builder.setContentTitle("title")
                .setContentText("hello")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(contentIntent);
        notificationManager.notify(1, builder.build());
    }

    String id = "my_channel_011";
    String CHANNEL_ID_STRING = "我是渠道名字11";

    private void notifyTest2() {
        Intent push = new Intent(this, HookTestActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, push, 0);

        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notification = null;
        if (SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel mChannel = new NotificationChannel(id, CHANNEL_ID_STRING, NotificationManager.IMPORTANCE_LOW);
            notificationManager.createNotificationChannel(mChannel);

            Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID_STRING);

            builder.setChannelId(id)
                    .setContentTitle("title1")
                    .setContentText("hello1")
                    .setContentIntent(contentIntent)
                    .setSmallIcon(R.mipmap.ic_launcher);
            notification = builder.build();

        } else {

            Notification.Builder builder = new Notification.Builder(this);
            builder.setContentTitle("title2")
                    .setContentText("hello2")
                    .setContentIntent(contentIntent)
                    .setSmallIcon(R.mipmap.ic_launcher);
            notification = builder.build();
        }
        notificationManager.notify(111123, notification);
    }

    public void hookNotificationManager(final Context context) throws Exception {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        //获取NotificationManager的getService()方法
        Method getService = NotificationManager.class.getDeclaredMethod("getService");
        //如果getService()方法是私有的，需要调用setAccessible(true)才可以操作
        getService.setAccessible(true);
        //得到原先的sService
        final Object sOriginService = getService.invoke(notificationManager);

        Class iNotiMngClz = Class.forName("android.app.INotificationManager");

        // 第二步：得到我们的动态代理对象( sService 是接口，所以我们可以使用动态代理)
        Object proxyNotiMng = Proxy.newProxyInstance(context.getClass().getClassLoader(), new
                Class[]{iNotiMngClz}, new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Log.i("fang " + TAG, "invoke: method:" + method);
                String name = method.getName();
                Log.i("fang " + TAG, "invoke: name=" + name);
                if (args != null && args.length > 0) {
                    for (Object arg : args) {
                        Log.i("fang " + TAG, "invoke: arg=" + arg);
                    }
                }
                Log.i("fang " + TAG, "invoke: 检测到有人发通知了");
                // 操作交由 sOriginService 处理，不拦截通知
                return method.invoke(sOriginService, args);
                // 拦截通知，什么也不做
                // return null;
                // 或者是根据通知的 Tag 和 ID 进行筛选
            }
        });

        // 第三步：偷梁换柱，使用 proxyNotiMng 替换系统的 sService
        Field sServiceField = NotificationManager.class.getDeclaredField("sService");
        sServiceField.setAccessible(true);
        sServiceField.set(notificationManager, proxyNotiMng);


    }

}
